# 错误的递归方式，没有给跳出条件
"""
def tell_story():
    print("从前有座山")
    print("上山有座庙")
    print("庙里有个老和尚")
    print("在给小和尚讲故事")
    print("讲的是什么呢?")
    tell_story()

tell_story()
"""
# 案例：计算x开始到10内的和
def text1(i:int):  # 3
    if i==10:
        return 10
    else:
        # 1 + 2
        return i+text1(i+1)
# r = text1(1)
#  案例2：计算x整数以内的和
def sum2(x):
    if x >1:
        value = x + sum2(x-1)
    else:
        value = 1
    return value
# sum2(5) # 5+4+3+2+1

# 匿名函数  lambda
# print(lambda x, y: x + y) # 返回的是一个地址值：<function <lambda> at 0x0000018907C2F160>
# print(lambda x, y: x + y()) # 同上效果
# 调用直接内存地址加括号(它虽然没有名字)+括号可以调用
"""
print((lambda x,y:x+y(1,2))) # <function <lambda> at 0x0000011D9B08F160>

# 匿名函数
f = lambda x,y:x+y
# x和y就是形参，x+y 就是表达式
print(f(x=1,y=2)) # 1+2

# 等同于下面的def函数
def add(x,y):
    return x+y
print(add(x=1, y=2))
"""
salarics={
    'long1':1000,
    'xiaolong3':3000,
    'xiaolong4':300000,
}
# 返回薪资最高，max比较字典的话，是按照key来算的
#ascii值 a=97 b=98 c=99 ..z = ？，A=65，B= 66，C=67.。。Z=？
# print(max(salarics)) # xiaolong3
"""
# 自定义函数联合内置函数max，求出最大的月薪
def func(name): # name 手动传入的形参
    return salarics[name]
# print(func('long1')) # 1000
print(max(salarics,key=func)) # xiaolong4
"""
# 内置函数max 联合lambda求出最大月薪
# 转化成lambda
"""
max比较字典的话，是一个一个的key
后面的key ，根据传递的内容进行大小比对
lambda name: salarics[name]
字典里面的name，就是字典需要传入的key，返回的是
key = [1000,3000,300000]
"""
"""
print(max(salarics, key=lambda age: salarics[age])) # xiaolong4

# 内置函数max 联合lambda求出最小月薪
print(min(salarics, key=lambda name: salarics[name])) # long1
"""
# print(sorted(salarics, key=lambda name: salarics[name], reverse=True))
s = [
    {'name':'龙仔','性别':'男','薪资':3000,'职位':'打工仔'},
    {'name':'曹賊','性别':'男','薪资':9000,'职位':'总经理'},
    {'name':'浩仔','性别':'男','薪资':8000,'职位':'副经理'},
    {'name':'雷子','性别':'男','薪资':5000,'职位':'督导'},
]
# print(s)
# 我想根据薪资进行排序，不使用内置方法，也不使用匿名函数
# 冒泡排序
"""
for i in range(len(s)): # 根据列表长度进行遍历
    for j in range(len(s)-1):
        if s[j]['薪资'] > s[j+1]['薪资']:
            s[j]['薪资'],s[j+1]['薪资'] = s[j+1]['薪资'],s[j]['薪资']
print(s)
"""
# 闭包函数

def outer():
    print("外面的函数正在运行")
    def inner():
        print("里面的函数正在运行")
    """
    没有加括号，就不算调用，这里就是一个地址值
    """
    return inner
# 调用
# outer() # 因为这里调用的子函数是地址值
# print(outer()) # 返回就是地址值 # 0x000001BFA14FF1F0
# 加一个括号调用它
# outer()() # 这样调用不是很规范
"""
inner = outer()
inner() # 这样调用比较规范，也易懂
"""

# 通过闭包，自增长数字
def add_num():
    x = 0 # 定义了一个0
    def l():
        """
        nonlocal 声明一下，使用的是外函数，改变它
        """
        nonlocal x
        x+=1
        return x
    return l
"""
a = add_num()
print(a) # 地址值 <function add_num.<locals>.l at 0x0000014B238CF310>
print(a()) # 1
print(a()) # 2
print(a()) # 3
"""
"""
外函数嵌套子函数
外函数返回的是子函数的地址值
形成闭包
"""

# 装饰器
# 需求：在不修改原来的代码，不改变调用方法的情况下，增加跑步的功能
def run():
    print("跑步")
    """
    装饰器原则第一：不可以修改原代码
    """
    # print("健身") # 违反了原则第一
# 跑步的方法，加上健身
def run1(): # 这不叫装饰器，违反了原则第二
    print("跑步")
    print("健身")
# run() # 我原来是run
# run1() # 你给我改成了run1 ，不符合我的需求，不是装饰器

name = '龙仔'
def run_1(name):
    print("===========")
    print("我是%s"%name)
    print("===========")
# run_1(name)
"""
我是被装饰器前面的代码
==============
我是龙仔
==============
我是装饰器后面的代码
"""
# 为上面的进行修饰，编写装饰器
def decorate(func):
    """
    :param func:  这里传递的func，实际上就是原来的方法
    :return:
    """
    def new_func(new_name):
        """
        :param new_name: new_name，就是原来的参数传递，因为原来有形参
        ，所以这里也要写上去
        :return:
        """
        print("我是被装饰器前面的代码")
        func(new_name) # 原来的方法调用
        print("我是装饰器后面的代码")
    return new_func
# d1 = decorate(run_1)
# d1("侯雯中")
# 原来的方法没有被改掉
# run_1("侯雯中")




"""
需求：
没有写清楚玩什么，但是这个play这个方法我还不想动，因为佳鑫在用，我是嘉诚，我不能动，不然会影响到他

我要加上：lol
佳鑫要加：猫咖
"""
def play(a):
    """
    :param a: a，地点
    :return:
    """
    print(f"去{a}玩")
def play_new(func):
    """
    :param func:  就是待修饰的方法
    :return:
    """
    def luoji(name,age):
        """
        :param a: 原来有参数，你别给人落下了
        :return:
        """
        func(name)
        print("lol")
        print(f"今年{age}岁")
        """
        执行顺序：
        func(a)，如果你前面有代码，就会先执行它，再执行func(a)本身的代码块
        如果后面有代码，就会在func(a)执行后，再执行它
        """
    return luoji

# 调用
# n_play = play_new(play)
# 输入形参，调用
# n_play("沈阳",19)
"""
执行顺序：
print(f"去{a}玩")
print("lol")
"""
# 时间装饰器案例
# 测试for循环从1加到9000000000000的时间
from datetime import datetime
"""
from：来自于哪个模块
datetime：时间模块
import：只是导入这个模块下的一个方法
datetime：datetime下的tdatetime方法
"""
from random import randint
"""
from：来自于哪个模块
random：随机模块
import：只是导入这个模块下的一个方法
randint：只是导入random下的randint这一个方法
"""
"""
from random import *
from：来自于哪个模块
random：随机模块
import * ：这里就是导入这一个模块下的所有方法
"""
"""
# random.randint() # 这么调用
# from方式导入的模块，省略了前面的库名称
ran_num = randint(10,20) # 从10~20之间随机返回一个数字
print(ran_num)
"""
# print(datetime) # 直接打印是一个datetime类型
# print(datetime.now()) # now，打印当前时间
# 时间装饰器

# fori 这个函数用来计算，从0~9000000000000的和

def run_time(func):
    """
    :param func:  先把要修饰的方法传进去
    :return:
    """
    def new_func(n):
        """
        :param n: 待修饰的函数里面，有一个n形参，这里拿过来不动
        :return:
        """
        start_time = datetime.now() # 开始时间
        func(n)
        end_time = datetime.now() # 结束时间
        time1 = end_time - start_time
        print("花费时间%s"%time1)
    return new_func
# r = run_time(fori)
# r(n)
"""
执行顺序：
start_time = datetime.now() # 开始时间
sum = 0
for i in range(1,n+1):
    sum+=i
print(sum)
end_time = datetime.now() # 结束时间
time1 = end_time - start_time
print("花费时间%s"%time1)
"""
# 简化装饰器的调用
n = 90000
@run_time # @是python里的一个语法糖，后面跟上装饰器的名称
def fori(n):
    sum = 0
    for i in range(1,n+1):
        sum+=i
    print(sum)
fori(n)


















